package parcel

import (
	"encoding/json"
	"github.com/duke-git/lancet/v2/fileutil"
	"github.com/dustin/go-humanize"
	"github.com/rs/zerolog/log"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"v3workshop/pkg/util"
)

const (
	MetadataPath = ".metadata/metadata.json"
)

var (
	ExcludePathMap = map[string]bool{
		".git":      true,
		".metadata": true,
	}
	ExcludeFileNameRe []*regexp.Regexp
)

func init() {
	pngSuffixRe, err := regexp.Compile(`\.png$`)
	if err != nil {
		log.Panic().Err(err).Send()
	}
	ExcludeFileNameRe = append(ExcludeFileNameRe, pngSuffixRe)
}

type Metadata struct {
	Name                 string        `json:"name"`
	Id                   string        `json:"id"`
	Version              string        `json:"version"`
	SupportedGameVersion string        `json:"supported_game_version"`
	Picture              string        `json:"picture"`
	ShortDescription     string        `json:"short_description"`
	Tags                 []string      `json:"tags"`
	Relationships        []interface{} `json:"relationships"`
	GameCustomData       struct {
		MultiplayerSynchronized bool `json:"multiplayer_synchronized"`
	} `json:"game_custom_data"`
}

type Parcel struct {
	Workspace string
	Id        string
	Metadata  *Metadata
}

func NewParcel(workspace string) *Parcel {
	return &Parcel{
		Workspace: workspace,
		Id:        path.Base(workspace),
	}
}

func (p *Parcel) GetMetadataPath() string {
	return path.Join(p.Workspace, MetadataPath)
}

func (p *Parcel) GetSize() string {
	size,err:= fileutil.DirSize(p.Workspace)
	if err!=nil{
		return ""
	}
	return humanize.Bytes(uint64(size))
}

func (p *Parcel) LoadMetadata() error {
	metadata := new(Metadata)
	defer func() {
		p.Metadata = metadata
	}()
	if !util.IsFileExists(p.GetMetadataPath()) {
		return nil
	}
	f, err := os.Open(p.GetMetadataPath())
	if err != nil {
		return nil
	}
	defer f.Close()
	err = json.NewDecoder(f).Decode(metadata)
	if err != nil {
		return err
	}
	return nil
}

func (p *Parcel) CopyToPath(targetPath string) error {
	err := filepath.Walk(p.Workspace, func(pathStr string, info os.FileInfo, err error) error {
		relPath, err := filepath.Rel(p.Workspace, pathStr)
		if err != nil {
			return err
		}
		displayPath := path.Join(path.Base(p.Workspace), relPath)
		if pathStr == p.Workspace {
			return nil
		}
		for _, re := range ExcludeFileNameRe {
			if re.MatchString(info.Name()) {
				log.Info().Str("path", displayPath).Msg("skip exclude file")
				return nil
			}
		}
		if info.IsDir() {
			if ExcludePathMap[relPath] {
				log.Info().Str("path", displayPath).Msg("skip exclude path")
				return filepath.SkipDir
			}
			targetDir := path.Join(targetPath, relPath)
			if !util.IsFileExists(targetDir) {
				err = os.MkdirAll(targetDir, os.ModePerm)
				if err != nil {
					return err
				}
			}
		} else {
			err = fileutil.CopyFile(pathStr, path.Join(targetPath, relPath))
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}
	return nil
}
